package com.chart.web.controller.chart;

import cn.hutool.core.util.XmlUtil;
import com.alipay.api.AlipayApiException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.chart.chart.domian.ChartOrders;
import com.chart.chart.domian.ChartPaidPackage;
import com.chart.chart.service.IChartCPaidPackageService;
import com.chart.chart.service.IChartOrdersService;
import com.chart.common.annotation.RepeatSubmit;
import com.chart.common.constant.CacheConstants;
import com.chart.common.core.controller.BaseController;
import com.chart.common.core.domain.AjaxResult;
import com.chart.common.core.domain.entity.SysUser;
import com.chart.common.core.domain.entity.UserCoinLog;
import com.chart.common.core.domain.model.LoginUser;
import com.chart.common.core.redis.RedisCache;
import com.chart.common.utils.*;
import com.chart.common.utils.ip.IpUtils;
import com.chart.framework.web.service.TokenService;
import com.chart.system.domain.SysUserOrder;
import com.chart.system.service.ISysUserOrderService;
import com.chart.system.service.ISysUserService;
import com.chart.system.service.IUserCoinLogsService;
import com.chart.web.controller.aliPay.AlipayUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * 图表套餐-微信支付
 *
 * @author chart
 */
@Slf4j
@RestController
@RequestMapping("/paid/chart")
public class ChartPaidPackageController extends BaseController {

    @Autowired
    private ISysUserService userService;

    @Autowired
    private IChartCPaidPackageService paidPackageService;

    @Autowired
    private ISysUserOrderService userOrderService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IChartOrdersService chartOrdersService;

    @Autowired
    private AlipayUtil alipayUtil;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private IUserCoinLogsService userCoinLogsService;


    // 令牌有效期（默认30分钟）
    @Value("${token.expireTime}")
    private int expireTime;

    /**
     * 微信公众号APPID
     */
    @Value("${wxpay.appid}")
    private String appid;

    /**
     * 微信公众号的商户号
     */
    @Value("${wxpay.wxpaymentaccount}")
    private String wxpaymentaccount;

    /**
     * 微信公众号的商户支付密钥
     */
    @Value("${wxpay.apikey}")
    private String apikey;

    /**
     * 下单接口
     */
    @Value("${wxpay.basePath}")
    private String basePath;

    /**
     * 回调接口
     */
    @Value("${wxpay.notifyUrl}")
    private String notifyUrl;

    //之前的放入到缓存
    @ApiOperation("付费套餐：列表")
    @GetMapping("/package/list")
    public AjaxResult list(ChartPaidPackage chartPaidPackage) {
        if (ObjectUtils.isEmpty(chartPaidPackage.getPackageId())) {
            List<ChartPaidPackage> list = redisCache.getCacheObject(CacheConstants.CHART_PACKAGES);
            return AjaxResult.success(list);
        }
        ChartPaidPackage paidPackage = redisCache.getCacheObject(CacheConstants.CHART_PACKAGES + chartPaidPackage.getPackageId());
        return AjaxResult.success(paidPackage);
    }


    //存到缓存中  待支付
    @RepeatSubmit(interval = 1000)//每隔一秒提交一次 1000毫秒
    @ApiOperation("付费套餐：预下单")
    @PostMapping(value = "/order")
    @Transactional
    public AjaxResult getorder(@RequestBody ChartPaidPackage chartPaidPackage) {
        // 判断 chartPaidPackage 非空参数校验
        if (chartPaidPackage == null) {
            log.error("预下单失败：提交的付费套餐信息为空:{}", chartPaidPackage);
            return AjaxResult.error("预下单失败：提交的付费套餐信息为空");
        }
        Map<String, Object> map = new HashMap<>();
        //获取当前用户
        Long userId = SecurityUtils.getUserId();
        if (SecurityUtils.isAdmin(userId)) {
            //封装返回值
            map.put("orderNum", "管理员无需付费");
            return AjaxResult.success(map);
        }
        if (chartPaidPackage.getPackageId() == 1) {
            ChartOrders orders = chartOrdersService.getOne(new LambdaQueryWrapper<ChartOrders>().eq(ChartOrders::getUserId, userId).eq(ChartOrders::getPackageId, 1));
            if (!ObjectUtils.isEmpty(orders)) {
                map.put("orderNum", "用户只能购买一次试用会员");
                return AjaxResult.success(map);
            }
        }
        ChartOrders chartOrders = new ChartOrders();
        chartOrders.setUserId(userId);//用户
        chartOrders.setOrderNum(getOutTradeNo());//订单号
        chartOrders.setPackageId(chartPaidPackage.getPackageId());//商品
//        chartOrders.setQuantity(1);//数量
        BigDecimal decimal = chartPaidPackage.getTotalPrice().multiply(new BigDecimal(100));
        chartOrders.setTotalPrice(decimal.intValue());//总价
        chartOrders.setOrderDetails(chartPaidPackage.getPackageName());//描述

        //新加
        chartOrders.setStatus(0);
        //设置订单详情格式
        try {
            //将订单信息放到缓存里 边
            redisCache.setCacheObject(CacheConstants.CHART_ORDER + chartOrders.getOrderNum(), chartOrders, 120, TimeUnit.MINUTES);
            //新加代码存储到数据库
            chartOrdersService.saveOrUpdate(chartOrders);
            map.put("orderNum", chartOrders.getOrderNum());//订单号
//                map.put("orderId", chartOrders.getOrderId());//订单id
            return AjaxResult.success(map);
        } catch (Exception e) {
            log.error("用户:{}预下单失败:{}", userId, e.getMessage());
            e.printStackTrace();
        }
        //封装返回值
        map.put("orderNum", "");
        return AjaxResult.success(map);
    }

    @ApiOperation("付费套餐：查询订单信息状态")
    @GetMapping(value = "/order/getStatus")
    @Transactional
    public AjaxResult SelectOrderStatus(String orderNum, Integer type, @RequestParam(value = "coins", required = false) Integer coins) {
        if (StringUtils.isEmpty(orderNum) || type == null) {
            log.error("订单查询失败，参数缺失：orderNum={},type={}",
                    StringUtils.isEmpty(orderNum) ? "为空" : orderNum,
                    type == null ? "为空" : type
            );
            return AjaxResult.error("订单查询失败，参数缺失");
        }
        // 0 未支付   1 已支付
        //判断订单是否已经处理
        String s = redisCache.getCacheObject(CacheConstants.VIP_OFFER + orderNum);
        if (!StringUtils.isEmpty(s)) {
            return AjaxResult.success(1);
        }
        //获取订单信息
        ChartOrders orders = chartOrdersService.getOne(new LambdaQueryWrapper<ChartOrders>().eq(ChartOrders::getOrderNum, orderNum));
        if (ObjectUtils.isEmpty(orders)) {
            return AjaxResult.success(0);
        }
        if (orders.getStatus() == 0) {
            return AjaxResult.success(0);
        }
        if (orders.getStatus() == 1 && orders.getIsConsume() == 1) {
            return AjaxResult.success(1);
        }
        if (orders.getStatus() == 1 && orders.getIsConsume() == 0) {
            ChartPaidPackage paidPackage = paidPackageService.getById(orders.getPackageId());
            paidPackage.setOrderId(orders.getOrderId());
            if (type == 1) {
                //获取订单vip的时间
                LocalDateTime experation = setExperation(paidPackage);
                if (!ObjectUtils.isEmpty(experation)) {
                    orders.setIsConsume(1);
                    boolean b = chartOrdersService.saveOrUpdate(orders);
                    if (b) {
                        //修改完用户信息  刷新token
                        refreshToken(experation, paidPackage.getPackageId());
                        //将处理过得订单信息进行缓存
                        redisCache.setCacheObject(CacheConstants.VIP_OFFER + orderNum, orderNum, 5, TimeUnit.MINUTES);
                        return AjaxResult.success(1);
                    }
                }
            } else if (type == 0) {
                //增加金币
                Long userId = SecurityUtils.getUserId();
                UserCoinLog userCoinLog = new UserCoinLog();
                userCoinLog.setUserId(userId);
                if (!ObjectUtils.isEmpty(coins)) {
                    userCoinLog.setCoins(coins);
                }
                userCoinLog.setBehavior("PAY");
                try {
                    userCoinLogsService.save(userCoinLog);
                } catch (Exception e) {
                    log.error("用户:{}增加金币失败:{}", userId, coins);
                    throw new RuntimeException(e);
                }
                return AjaxResult.success(1);
            }

        }
        return AjaxResult.success(1);
    }

    /**
     * 购买金币
     */
//    @ApiOperation("付费套餐：查询订单信息状态")
//    @GetMapping(value = "/order/getStatusCoins")
//    @Transactional
//    public AjaxResult SelectOrderStatus(String orderNum,  @RequestParam(value = "coins") Integer coins) {
//
//        if(StringUtils.isEmpty(orderNum)){
//            return AjaxResult.error(400,"订单号为空，请重试");
//        }
//        // 校验 coins 是否为 null 或者小于等于 0
//        if (coins == null || coins <= 0) {
//            return AjaxResult.error(400, "无效的 coins 参数，请提供一个正整数值");
//        }
//
//
//        // 0 未支付   1 已支付
//        //判断订单是否已经处理
//        String s = redisCache.getCacheObject(CacheConstants.VIP_OFFER + orderNum);
//        if (!StringUtils.isEmpty(s)) {
//            return AjaxResult.success(1);
//        }
//        //获取订单信息
//        ChartOrders orders = chartOrdersService.getOne(new LambdaQueryWrapper<ChartOrders>().eq(ChartOrders::getOrderNum, orderNum));
//        if (ObjectUtils.isEmpty(orders)) {
//            return AjaxResult.success(0);
//        }
//        if (orders.getStatus() == 0) {
//            return AjaxResult.success(0);
//        }
//        if (orders.getStatus() == 1 && orders.getIsConsume() == 1) {
//            return AjaxResult.success(1);
//        }
//        if (orders.getStatus() == 1 && orders.getIsConsume() == 0) {
//            ChartPaidPackage paidPackage = paidPackageService.getById(orders.getPackageId());
//            paidPackage.setOrderId(orders.getOrderId());
//
//            boolean b = chartOrdersService.saveOrUpdate(orders);
//            if (b) {
//                //增加金币
//                Long userId = SecurityUtils.getUserId();
//                UserCoinLog userCoinLog = new UserCoinLog();
//                userCoinLog.setUserId(userId);
//                if (!ObjectUtils.isEmpty(coins)) {
//                    userCoinLog.setCoins(coins);
//                }
//                userCoinLog.setBehavior("PAY");
//                try {
//                    userCoinLogsService.save(userCoinLog);
//                } catch (Exception e) {
//                    log.error("用户:{}增加金币失败:{}", userId, coins);
//                    throw new RuntimeException(e);
//                }
//            }
//                return AjaxResult.success(1);
//
//        }
//        return AjaxResult.success(0);
//    }
//



    /**
     * 购买VIP
     * @param orderNum
     * @return
     */
//    @ApiOperation("付费套餐：查询订单信息状态")
//    @GetMapping(value = "/order/getStatus")
//    @Transactional
//    public AjaxResult SelectOrderStatus(String orderNum) {
//
//       if(StringUtils.isEmpty(orderNum)){
//           return AjaxResult.error(400,"订单号为空，请重试");
//       }
//
//        // 0 未支付   1 已支付
//        //判断订单是否已经处理
//        String s = redisCache.getCacheObject(CacheConstants.VIP_OFFER + orderNum);
//        if (!StringUtils.isEmpty(s)) {
//            return AjaxResult.success(1);
//        }
//        //获取订单信息
//        ChartOrders orders = chartOrdersService.getOne(new LambdaQueryWrapper<ChartOrders>().eq(ChartOrders::getOrderNum,orderNum));
//        if (ObjectUtils.isEmpty(orders)) {
//            return AjaxResult.success(0);
//        }
//        if (orders.getStatus()==0) {
//            return AjaxResult.success(0);
//        }
//        if (orders.getStatus()==1 && orders.getIsConsume()==1) {
//            return AjaxResult.success(1);
//        }
//        if (orders.getStatus()==1 && orders.getIsConsume()==0) {
//            ChartPaidPackage paidPackage = paidPackageService.getById(orders.getPackageId());
//            paidPackage.setOrderId(orders.getOrderId());
//            //获取订单vip的时间
//            LocalDateTime experation = setExperation(paidPackage);
//            if (!ObjectUtils.isEmpty(experation)) {
//                orders.setIsConsume(1);
//                boolean b = chartOrdersService.saveOrUpdate(orders);
//                if (b) {
//                    //修改完用户信息  刷新token
//                    refreshToken(experation,paidPackage.getPackageId());
//                    //将处理过得订单信息进行缓存
//                    redisCache.setCacheObject(CacheConstants.VIP_OFFER+orderNum,orderNum, 5,TimeUnit.MINUTES);
//                    return AjaxResult.success(1);
//                }
//            }
//        }
//        return AjaxResult.success(0);
//    }



    /**
     * 微信支付主接口
     */
    @RepeatSubmit(interval = 3000)
    @ApiOperation("付费套餐：支付主接口")
    @GetMapping(value = "/order/pay")
    public AjaxResult createQRCode(HttpServletResponse response, String orderNum) {
        if (StringUtils.isEmpty(orderNum)) {
            log.error("微信支付主接口/order/pay订单号:{}为空", orderNum);
            return AjaxResult.error("订单号为空");
        }

        ServletOutputStream sos = null;
        try {
            ChartOrders orders = redisCache.getCacheObject(CacheConstants.CHART_ORDER + orderNum);
            if (ObjectUtils.isEmpty(orders)) {
                return AjaxResult.error("订单已经过期请重新选择套餐！");
            }
            String orderInfo = createOrderInfo(orders);
            String code_url = httpOrder(orderInfo);//调用统一下单接口
            sos = response.getOutputStream();
            //生成二维码
            QRCodeUtils.encode(code_url, sos);
            return AjaxResult.success();
        } catch (IOException e) {
            log.error("订单号:{}支付失败:{}", orderNum, e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            log.error("订单号:{}支付失败:{}", orderNum, e.getMessage());
            e.printStackTrace();
        }
        return AjaxResult.error();
    }


    /**
     * 支付宝支付接口
     * out_trade_no自己生成的
     *
     * @param response
     * @param orderNum
     * @return
     */
//    @GetMapping(value = "/order/alipay")
//    @ApiOperation("付费套餐：支付宝支付主接口")
//    public AjaxResult createAlipayQRCode(HttpServletResponse response, String orderNum) {
//        if (StringUtils.isEmpty(orderNum)) {
//            log.error("支付宝支付接口/order/alipay订单号:{}为空", orderNum);
//            return AjaxResult.error("订单号为空");
//        }
//        ServletOutputStream sos = null;
//        try {
//            // 获取订单信息
//            ChartOrders orders = redisCache.getCacheObject(CacheConstants.CHART_ORDER + orderNum);
//            if (ObjectUtils.isEmpty(orders)) {
//                return AjaxResult.error("订单已经过期，请重新选择套餐！");
//            }
//            // 获取订单详情
//            // 商品描述
//            String orderDetails = orders.getOrderDetails();
//            // 订单号
//            String orderNums = orders.getOrderNum();
//            // 总金额
//            Integer totalPrice = orders.getTotalPrice();
//            // 转换为字符串类型
//            String price = totalPrice.toString();
//            // 调用支付宝支付接口获取二维码URL
//            String qrCodeUrl = alipayUtil.aliPay(orderNums, price, orderDetails);
//            if (qrCodeUrl == null) {
//                return AjaxResult.error("获取二维码URL失败！");
//            }
//
//            // 设置响应内容类型为图片
//            response.setContentType("image/png");
//
//            // 获取输出流并生成二维码
//            sos = response.getOutputStream();
//            QRCodeUtils.encode(qrCodeUrl, sos);
//            sos.flush();
//
//            // 返回成功，二维码已经写入响应
//            return AjaxResult.success();
//        } catch (IOException e) {
//            log.error("订单号:{}二维码生成失败:{}", orderNum, e.getMessage());
//            e.printStackTrace();
//            return AjaxResult.error("二维码生成失败！");
//        } catch (Exception e) {
//            e.printStackTrace();
//            log.error("订单号:{}调用支付宝接口异常:{}", orderNum, e.getMessage());
//            return AjaxResult.error("调用支付宝接口异常！");
//        } finally {
//            if (sos != null) {
//                try {
//                    sos.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
//    }


    /**
     * 支付宝支付接口
     * out_trade_no自己生成的
     *
     * @param response
     * @param orderNum
     * @return
     */
    @GetMapping(value = "/order/alipay")
    @ApiOperation("付费套餐：支付宝支付主接口")
    public void createAlipayQRCode(HttpServletResponse response, String orderNum) {

        if (StringUtils.isEmpty(orderNum)) {
            log.error("支付宝支付接口/order/alipay订单号:{}为空", orderNum);
            try {
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write("{\"code\": 500, \"message\": \"订单号为空\"}");
            } catch (IOException e) {
                log.error("响应输出失败:{}", e.getMessage());
            }
            return;
        }

        ServletOutputStream sos = null;
        try {
            // 获取订单信息
            ChartOrders orders = redisCache.getCacheObject(CacheConstants.CHART_ORDER + orderNum);
            if (ObjectUtils.isEmpty(orders)) {
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write("{\"code\": 500, \"message\": \"订单已经过期，请重新选择套餐！\"}");
                return;
            }

            // 获取订单详情
            String orderDetails = orders.getOrderDetails();
            String orderNums = orders.getOrderNum();
            Integer totalPrice = orders.getTotalPrice();
            String price = totalPrice.toString();

            // 调用支付宝支付接口获取二维码URL
            String qrCodeUrl = alipayUtil.aliPay(orderNums, price, orderDetails);
            if (qrCodeUrl == null) {
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write("{\"code\": 500, \"message\": \"获取二维码URL失败！\"}");
                return;
            }

            // 设置响应内容类型为图片
            response.setContentType("image/png");

            // 获取输出流并生成二维码
            sos = response.getOutputStream();
            QRCodeUtils.encode(qrCodeUrl, sos);
            sos.flush();
            log.info("订单号orderNum={}生成二维码成功",orderNum);
        } catch (IOException e) {
            log.error("订单号:{}二维码生成失败:{}", orderNum, e.getMessage());
            try {
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write("{\"code\": 500, \"message\": \"二维码生成失败！\"}");
            } catch (IOException ioException) {
                log.error("响应输出失败:{}", ioException.getMessage());
            }
        } catch (Exception e) {
            log.error("订单号:{}调用支付宝接口异常:{}", orderNum, e.getMessage());
            try {
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write("{\"code\": 500, \"message\": \"调用支付宝接口异常！\"}");
            } catch (IOException ioException) {
                log.error("响应输出失败:{}", ioException.getMessage());
            }
        } finally {
            if (sos != null) {
                try {
                    sos.close();
                } catch (IOException e) {
                    log.error("输出流关闭失败:{}", e.getMessage());
                }
            }
        }
    }


    /**
     * 支付宝查询支付状态接口
     * @param
     * @return
     * @throws AlipayApiException
     */
    @GetMapping("queryOrderDetails")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult queryOrderDetails(String orderNum, Integer type, Integer coins) throws AlipayApiException, JsonProcessingException {
        if (StringUtils.isEmpty(orderNum) || type == null || coins == null) {
            log.warn("支付宝查询支付状态接口参数缺失: orderNum={}, type={}, coins={}",
                    StringUtils.isEmpty(orderNum) ? "为空" : orderNum,
                    type == null ? "为空" : type,
                    coins == null ? "为空" : coins);
            return AjaxResult.success("参数不完整");
        }
        String queryOrder = alipayUtil.queryOrderTwo(orderNum);
        if (StringUtils.isEmpty(queryOrder)) {
            log.error("支付宝未查询到该订单信息");
            return AjaxResult.error("支付宝未查询到该订单信息");
        }
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode = objectMapper.readTree(queryOrder);
        JsonNode alipayTradeQueryResponse = jsonNode.path("alipay_trade_query_response");
        // 检查trade_status是否存在，并且其值为TRADE_SUCCESS
        JsonNode tradeStatus = alipayTradeQueryResponse.path("trade_status");
        if (tradeStatus.isTextual() && "TRADE_SUCCESS".equals(tradeStatus.asText())) {

            //获取订单信息之前进行数量校验
            LambdaQueryWrapper<ChartOrders> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ChartOrders::getOrderNum, orderNum);
            // 查询订单信息之前进行数量校验
            List<ChartOrders> list = chartOrdersService.list(queryWrapper);
            if (list.size() > 1) {
                logger.error("订单号重复，存在多个订单，订单号：{}", orderNum);
                return AjaxResult.error("查询出多条订单");
            }
            //1  支付宝成功   0支付失败
            //获取订单信息
            ChartOrders orders = chartOrdersService.getOne(new LambdaQueryWrapper<ChartOrders>().eq(ChartOrders::getOrderNum, orderNum));
            orders.setStatus(1);
            ChartPaidPackage paidPackage = paidPackageService.getById(orders.getPackageId());
            // 校验 paidPackage 是否存在
            if (paidPackage == null) {
                log.error("数据库未找到付费套餐信息订单的信息:{}", orderNum);
                return AjaxResult.error("数据库未找到对应的付费套餐信息");
            }
            paidPackage.setOrderId(orders.getOrderId());
            if (type == 1) {
                //获取订单vip的时间
                LocalDateTime experation = setExperation(paidPackage);
                if (!ObjectUtils.isEmpty(experation)) {
                    orders.setIsConsume(1);
                    boolean b = chartOrdersService.saveOrUpdate(orders);
                    if (b) {
                        //修改完用户信息  刷新token
                        refreshToken(experation, paidPackage.getPackageId());
                        //将处理过得订单信息进行缓存
                        redisCache.setCacheObject(CacheConstants.VIP_OFFER + orderNum, orderNum, 5, TimeUnit.MINUTES);
                        return AjaxResult.success(1);
                    } else {
                        log.error("获取订单信息:{}异常", orderNum);
                    }

                }
            } else if (type == 0) {
                boolean b = chartOrdersService.saveOrUpdate(orders);
                if (b) {
                    //增加金币
                    Long userId = SecurityUtils.getUserId();
                    UserCoinLog userCoinLog = new UserCoinLog();
                    userCoinLog.setUserId(userId);
                    userCoinLog.setCoins(coins);
                    userCoinLog.setBehavior("PAY");
                    try {
                        userCoinLogsService.save(userCoinLog);
                        log.info("用户:{}增加金币成功", userId);
                    } catch (Exception e) {
                        log.error("用户:{}增加金币失败", userId, e.getMessage());
                        throw new RuntimeException(e);
                    }
                }

                return AjaxResult.success(1);
            }
            return AjaxResult.success(1);
        } else {
            AjaxResult.success(0);
        }
        return AjaxResult.success();
    }

    /**
     * 支付宝自定义付款
     *
     * @param response
     * @param orderNum
     * @return
     */
    @GetMapping(value = "/alipay/customPayment")
    @ApiOperation("付费套餐：支付宝支付主接口")
    public AjaxResult customPayment(HttpServletResponse response, String orderNum, String price) {
        if (StringUtils.isEmpty(orderNum) || StringUtils.isEmpty(price)) {
            log.error("支付宝自定义付款失败，参数为空orderNum={},price={}",
                    StringUtils.isEmpty(orderNum) ? "为空" : orderNum,
                    StringUtils.isEmpty(price) ? "为空" : price
            );
            return AjaxResult.error("支付宝自定义付款失败，参数缺失");
        }
        OutputStream sos = null;
        try {
            if (orderNum == null || orderNum.isEmpty()) {
                return AjaxResult.error("订单号不能为空");
            }
            String orderDetails = "支付宝自定义支付";
            // 调用支付宝支付接口获取二维码URL
            String qrCodeUrl = alipayUtil.customPayment(orderNum, price, orderDetails);
            if (qrCodeUrl == null) {
                return AjaxResult.error("获取二维码URL失败！");
            }
            // 设置响应内容类型为图片
            response.setContentType("image/png");
            // 获取输出流并生成二维码
            sos = response.getOutputStream();
            //生成二维码
            QRCodeUtils.encode(qrCodeUrl, sos);
            sos.flush();
            // 返回成功，二维码已经写入响应
            return AjaxResult.success();
        } catch (IOException e) {
            e.printStackTrace();
            log.error("订单号orderNum：{},二维码生成失败:{}", orderNum, e.getMessage());
            return AjaxResult.error("二维码生成失败！");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("订单号orderNum：{},调用支付宝接口异常:{}", orderNum, e.getMessage());
            return AjaxResult.error("调用支付宝接口异常！");
        } finally {
            if (sos != null) {
                try {
                    sos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 微信支付自定义付款接口
     */
    @RepeatSubmit(interval = 3000)
    @ApiOperation("付费套餐：支付主接口")
    @GetMapping(value = "wechat/CustomPayment")
    public AjaxResult wechatCustomPayment(HttpServletResponse response, String orderNum, String totalPrice) {
        if (StringUtils.isEmpty(orderNum) || StringUtils.isEmpty(totalPrice)) {
            log.error("微信自定义付款接口失败，参数不全orderNum={},totalPrice={}",
                    StringUtils.isEmpty(orderNum) ? "为空" : orderNum,
                    StringUtils.isEmpty(totalPrice) ? "为空" : totalPrice
            );
            return AjaxResult.error("微信自定义付款接口失败，参数不全");
        }
        ServletOutputStream sos = null;
        try {
            String orderDetails = "微信自定义支付";
            ChartOrders chartOrders = new ChartOrders();
            chartOrders.setOrderDetails(orderDetails);
            chartOrders.setOrderNum(orderNum);

            String orderInfo = wechatCustomPayments(chartOrders, totalPrice);
            String code_url = httpOrder(orderInfo);//调用统一下单接口
            sos = response.getOutputStream();
            //生成二维码
            QRCodeUtils.encode(code_url, sos);
            return AjaxResult.success();
        } catch (IOException e) {
            log.error("微信自定义支付生成二维码异常", e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AjaxResult.error();
    }


    /**
     * 支付宝
     * 用户支付成功以后调用这个接口插入数据库保存订单
     */
    @Transactional //自动回滚机制
    @PostMapping(value = "/alipayCallBack")
    public Map<String, String> alipayCallBack(HttpServletRequest request, String orderNum) {

        if (StringUtils.isEmpty(orderNum)) {
            log.error("保存订单失败，orderNum为空，无法处理订单回调");
        }

        Map<String, String> resultMap = new HashMap<>();
        //查询数据前对getOne进行参数校验
        LambdaQueryWrapper<ChartOrders> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ChartOrders::getOrderNum, orderNum);
        List<ChartOrders> list = chartOrdersService.list(wrapper);
        if (list.size() > 1) {
            log.error("支付宝/alipayCallBack接口查询出来orderNum:{}数量大于1", orderNum);
        }
        ChartOrders order = chartOrdersService.getOne(new LambdaQueryWrapper<ChartOrders>().eq(ChartOrders::getOrderNum, orderNum));
        //判断订单是否已经保存
        if (ObjectUtils.isEmpty(order)) {
            //判断是否有订单生成
            ChartOrders orders = redisCache.getCacheObject(CacheConstants.CHART_ORDER + orderNum);
            if (!ObjectUtils.isEmpty(orders)) {
                orders.setStatus(1);
                boolean b = chartOrdersService.saveOrUpdate(orders);
                if (b) {
                    resultMap.put("result_code", "SUCCESS");
                    resultMap.put("result_msg", "OK");
                    return resultMap;
                } else {
                    resultMap.put("result_code", "FAIL");
                    resultMap.put("result_msg", "数据处理失败");
                    return resultMap;
                }
            }
        } else {
            resultMap.put("result_code", "SUCCESS");
            resultMap.put("result_msg", "OK");
            return resultMap;
        }

        return resultMap;
    }


    private void updateOrderStatus(Long orderId, int status) {
        ChartOrders orderToUpdate = new ChartOrders();
        orderToUpdate.setOrderId(orderId);
        orderToUpdate.setStatus(status);  // 将状态更新为1
        orderToUpdate.setUpdateTime(new Date());  // 更新操作时间
        chartOrdersService.updateById(orderToUpdate);  // 调用更新方法更新数据库记录
    }


    @PostMapping(value = "/wxPayCallBack.do")
    @Transactional
    public String wxPayCallBack(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> resultMap = new HashMap<>();

        try {
            // 读取微信的回调信息
            InputStream inStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            outSteam.close();
            inStream.close();

            // 将结果转为字符串，并解析为Map
            String result = new String(outSteam.toByteArray(), "utf-8");
            Map<String, Object> map = XmlUtil.xmlToMap(result);
            // 检查微信返回的支付结果
            if ("SUCCESS".equals(map.get("result_code"))) {
                String out_trade_no = map.get("out_trade_no").toString();  // 获取订单号
                // 查询数据库中的订单
                ChartOrders order = chartOrdersService.getOne(new LambdaQueryWrapper<ChartOrders>()
                        .eq(ChartOrders::getOrderNum, out_trade_no));

                if (ObjectUtils.isEmpty(order)) {
                    // 数据库中找不到订单时，从缓存中获取订单
                    ChartOrders cachedOrder = redisCache.getCacheObject(CacheConstants.CHART_ORDER + out_trade_no);

                    if (!ObjectUtils.isEmpty(cachedOrder)) {
                        // 更新缓存中的订单状态
                        cachedOrder.setStatus(1);
                        boolean dbSaveSuccess = chartOrdersService.saveOrUpdate(cachedOrder);  // 保存到数据库

                        if (dbSaveSuccess) {
                            // 更新成功后，更新缓存中的状态为1
                            redisCache.setCacheObject(CacheConstants.CHART_ORDER + out_trade_no, cachedOrder);

                            // 返回给微信支付成功的通知
                            resultMap.put("result_code", "SUCCESS");
                            resultMap.put("result_msg", "OK");
                            return XmlUtil.mapToXmlStr(resultMap);
                        } else {
                            resultMap.put("result_code", "FAIL");
                            resultMap.put("result_msg", "订单更新数据库失败");
                            log.error("微信回调保存数据库失败:{}", cachedOrder);
                            return XmlUtil.mapToXmlStr(resultMap);
                        }
                    } else {
                        resultMap.put("result_code", "FAIL");
                        resultMap.put("result_msg", "订单不存在");
                        log.error("微信回调订单不存在:{}", cachedOrder.getOrderNum());
                        return XmlUtil.mapToXmlStr(resultMap);
                    }
                } else {
                    // 订单已存在于数据库，检查状态
                    if (order.getStatus() != 1) {
                        order.setStatus(1);  // 更新订单状态为1
                        try {
                            chartOrdersService.saveOrUpdate(order);
                        } catch (Exception e) {
                            log.error("订单:{}保存数据库失败", order);
                            throw new RuntimeException(e);
                        }
                        // 同步更新缓存中的订单状态为1
                        redisCache.setCacheObject(CacheConstants.CHART_ORDER + out_trade_no, order);
                    }

                    // 返回给微信支付成功的通知
                    resultMap.put("result_code", "SUCCESS");
                    resultMap.put("result_msg", "OK");
                    return XmlUtil.mapToXmlStr(resultMap);
                }
            } else {
                resultMap.put("result_code", "FAIL");
                resultMap.put("result_msg", "支付失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            resultMap.put("result_code", "FAIL");
            resultMap.put("result_msg", "处理异常");
        }

        // 默认返回失败
        return XmlUtil.mapToXmlStr(resultMap);
    }


    // 新增的辅助方法，用于更新 chart_orders 表的 status 字段


    /**
     * 支付宝支付成功回调接口
     *
     * @param trade_no
     * @param total_amount
     * @param trade_status
     */
    @PostMapping("/notify")
    public void notifyUrl(String trade_no, String total_amount, String trade_status) {
        System.err.println("收到支付宝的反馈" + "支付宝订单编号：" + trade_no + ", 订单金额： " + total_amount + ",订单状态：" + trade_status);
    }


    //生成订单信息
    private String createOrderInfo(ChartOrders orders) throws Exception {
//        ChartOrders orders = chartOrdersService.getOne(new LambdaQueryWrapper<ChartOrders>().eq(ChartOrders::getOrderNum,orderNum));
        //生成订单对象
        Map<String, Object> map = new HashMap<>();
        map.put("appid", appid);//公众账号ID
        map.put("mch_id", wxpaymentaccount);//商户号
        map.put("body", orders.getOrderDetails());//商品描述
        map.put("nonce_str", NonceUtils.createNonce(32));
        map.put("notify_url", notifyUrl);//通知地址
        map.put("out_trade_no", orders.getOrderNum());//订单号
        map.put("spbill_create_ip", IpUtils.getIpAddr());//终端ip
        map.put("trade_type", "NATIVE");//交易类型
        map.put("total_fee", orders.getTotalPrice());//总金额
        String sign = createSign(map, apikey, "MD5");
        map.put("sign", sign);//签名
        //将订单对象转为xml格式
        String s = null;
        try {
            return XmlUtil.mapToXmlStr(map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new String(s.getBytes("UTF-8"));
    }

    private String wechatCustomPayments(ChartOrders orders, String totalPrice) throws Exception {
        // 将价格字符串转换为浮点数，然后乘以100，转为整数分
        int totalFeeInCents = (int) (Double.parseDouble(totalPrice) * 100);

//        ChartOrders orders = chartOrdersService.getOne(new LambdaQueryWrapper<ChartOrders>().eq(ChartOrders::getOrderNum,orderNum));
        //生成订单对象
        Map<String, Object> map = new HashMap<>();
        map.put("appid", appid);//公众账号ID
        map.put("mch_id", wxpaymentaccount);//商户号
        map.put("body", orders.getOrderDetails());//商品描述
        map.put("nonce_str", NonceUtils.createNonce(32));
        map.put("notify_url", notifyUrl);//通知地址
        map.put("out_trade_no", orders.getOrderNum());//订单号
        map.put("spbill_create_ip", IpUtils.getIpAddr());//终端ip
        map.put("trade_type", "NATIVE");//交易类型
        map.put("total_fee", totalFeeInCents);//总金额
        String sign = createSign(map, apikey, "MD5");
        map.put("sign", sign);//签名
        //将订单对象转为xml格式
        String s = null;
        try {
            return XmlUtil.mapToXmlStr(map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new String(s.getBytes("UTF-8"));
    }


    /**
     * 调统一下单API
     *
     * @param orderInfo
     * @return
     */
    private String httpOrder(String orderInfo) {
        try {
            HttpURLConnection conn = (HttpURLConnection) new URL(basePath).openConnection();
            //加入数据
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);

            BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());
            buffOutStr.write(orderInfo.getBytes("UTF-8"));
            buffOutStr.flush();
            buffOutStr.close();

            //获取输入流
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

            String line = null;
            StringBuffer sb = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }

            Map<String, Object> map = XmlUtil.xmlToMap(sb.toString());
            String return_msg = map.get("return_msg").toString();
//            System.out.println(return_msg);
            String return_code = map.get("return_code").toString();
            String code_url = map.get("code_url").toString();
            //根据微信文档return_code 和result_code都为SUCCESS的时候才会返回code_url
            if (null != map && "SUCCESS".equals(return_code)) {
                return code_url;
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    //修改用户vip信息
    private LocalDateTime setExperation(ChartPaidPackage chartPaidPackage) {
        Long userId = SecurityUtils.getUserId();
        LocalDateTime newTime = LocalDateTime.now();
        Long addTime = chartPaidPackage.getPackageValue();
        Long orderId = chartPaidPackage.getOrderId();
        LocalDateTime newExpirTime = null;
        boolean b = false;
        SysUserOrder userOrder = null;
        //判断用户是否是vip
        if (SecurityUtils.isVip()) {
            userOrder = userOrderService.getOne(new LambdaQueryWrapper<SysUserOrder>().eq(SysUserOrder::getUserId, userId));
            LocalDateTime expirTime = userOrder.getExpirationTime();
            //VIP还没到期
            if (expirTime.isAfter(newTime)) {
                newExpirTime = expirTime.plusSeconds(addTime / 1000);
            } else {
                newExpirTime = newTime.plusSeconds(addTime / 1000);
            }
            userOrder.setOrderId(orderId);
            userOrder.setExpirationTime(newExpirTime);

            if (chartPaidPackage.getPackageId() == 1) {
                SysUser user = userService.getById(userId);
                if (user.getIsApplyPackage() == 0) {
                    user.setIsApplyPackage(1);
                }
                boolean b1 = userService.saveOrUpdate(user);
            }

            b = userOrderService.saveOrUpdate(userOrder);

        } else {
            newExpirTime = newTime.plusSeconds(addTime / 1000);
            userOrder = new SysUserOrder();
            userOrder.setUserId(userId);
            userOrder.setOrderId(orderId);
            userOrder.setExpirationTime(newExpirTime);

            SysUser user = userService.getById(userId);
            user.setIsVip(1);
            if (chartPaidPackage.getPackageId() == 1) {
                user.setIsApplyPackage(1);
            }
            boolean b1 = userService.saveOrUpdate(user);
            if (b1) {
                b = userOrderService.saveOrUpdate(userOrder);
            }
        }
        if (b) {
            return newExpirTime;
        }
        return null;
    }


    //将套餐信息进行缓存
    @PostConstruct
    private void extracted() {
        List<ChartPaidPackage> list = paidPackageService.list(new LambdaQueryWrapper<ChartPaidPackage>().ne(ChartPaidPackage::getStatus, 1));
        list.forEach(e -> {
            redisCache.setCacheObject(CacheConstants.CHART_PACKAGES + e.getPackageId(), e);
        });
        redisCache.setCacheObject(CacheConstants.CHART_PACKAGES, list);
    }


    /**
     * 生成16位随机订单号
     *
     * @return key
     */
    private static String getOutTradeNo() {
        SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
        Date date = new Date();
        String key = format.format(date);
        Random r = new Random();
        key = key + r.nextInt();
        key = key.replaceAll("-", "").substring(0, 15);
        return key;
    }


    /**
     * 生成签名. 注意，若含有sign_type字段，必须和signType参数保持一致。
     *
     * @param data     待签名数据
     * @param key      API密钥
     * @param signType 签名方式
     * @return 签名
     */
    private static String createSign(final Map<String, Object> data, String key, String signType) throws Exception {
        //根据规则创建可排序的map集合
        Set<String> keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals("") || ObjectUtils.isEmpty(k)) {
                continue;
            }
            String s = data.get(k).toString();
            if (!ObjectUtils.isEmpty(s) && s.trim().length() > 0) // 参数值为空，则不参与签名
            {
                sb.append(k).append("=").append(s.trim()).append("&");
            }
        }
        sb.append("key=").append(key);
        //转换UTF-8
        String str = new String(sb.toString().getBytes("UTF-8"));
        if ("MD5".equals(signType)) {
            return md5(sb.toString()).toUpperCase();
        } else if ("HMACSHA256".equals(signType)) {
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
            sha256_HMAC.init(secret_key);
            byte[] array = sha256_HMAC.doFinal(str.getBytes("UTF-8"));
            StringBuilder sb2 = new StringBuilder();
            for (byte item : array) {
                sb2.append(Hex.encodeHexString(new byte[]{item}));
            }
            return sb2.toString();
        } else {
            throw new RuntimeException();
        }
    }


    /**
     * md5常用工具类
     *
     * @param data
     * @return
     */
    private static String md5(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b & 0xFF));
        }
        return sb.toString();
    }

    //每天凌晨自动处理过期的vip
    @Scheduled(cron = "0 0 0 1/1 * ? ")
    public void checkVip() {
        List<SysUser> newList = new ArrayList<>();
        //获取所有会员数据
        List<SysUser> VIPList = userService.list(new LambdaQueryWrapper<SysUser>().eq(SysUser::getIsVip, 1));
        VIPList.forEach(e -> {
            //根据id去查询vip订单数据
            SysUserOrder userOrder = userOrderService.getOne(new LambdaQueryWrapper<SysUserOrder>().eq(SysUserOrder::getUserId, e.getUserId()));
            //如果数据存在
            if (!ObjectUtils.isEmpty(userOrder)) {
                //获取vip过期时间比较
                LocalDateTime expirTime = userOrder.getExpirationTime();
                LocalDateTime now = LocalDateTime.now();
                if (expirTime.isBefore(now)) {
                    e.setIsVip(0);
                    newList.add(e);
                }
            }
        });
        userService.saveOrUpdateBatch(newList);

    }

    /**
     * 刷新令牌有效期
     *
     * @param experation 刷新会员时间
     */
    public void refreshToken(LocalDateTime experation, Long packageId) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        if (!SecurityUtils.isVip()) {
            user.setIsVip(1);
            if (packageId == 1) {
                user.setIsApplyPackage(1);
            }
        } else {
            if (user.getIsApplyPackage() == 0 && packageId == 1) {
                user.setIsApplyPackage(1);
            }
        }
        user.setExpirationTime(experation);
        // 根据uuid将loginUser缓存
        String userKey = tokenService.getTokenKey1(loginUser.getToken());

        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
    }


}


